//
// Created by 77873 on 2020/9/28 0028.
//


#include "MineVideo.h"

MineVideo::MineVideo(MinePlayStatus *playStatu, MineCallJava *callJava) {
    this->playStatus = playStatu;
    this->mineCallJava = callJava;
    queue = new MineQueue(playStatu);
}

MineVideo::~MineVideo() {

}


void *playVideo(void *data) {
    MineVideo *video = static_cast<MineVideo *>(data);
    while (video->playStatus != NULL && !video->playStatus->exit) {
        if (video->playStatus->seek) {
            av_usleep(1000 * 100);
            continue;
        }
        if (video->queue->getQueueSize() == 0) {
            if (!video->playStatus->load) {
                video->playStatus->load = true;
                video->mineCallJava->onCallLoad(CHILD_THREAD, true);
            }
            av_usleep(1000 * 100);
            continue;
        } else {
            if (video->playStatus->load) {
                video->playStatus->load = false;
                video->mineCallJava->onCallLoad(CHILD_THREAD, false);
            }
        }
        AVPacket *avPacket = av_packet_alloc();
        if (video->queue->outAvpacket(avPacket) != 0) {
            av_packet_free(&avPacket);
            av_free(avPacket);
            continue;
        }

        if (avcodec_send_packet(video->avCodecContext, avPacket) != 0) {
            av_packet_free(&avPacket);
            av_free(avPacket);
            continue;
        }
        AVFrame *avFrame = av_frame_alloc();
        if (avcodec_receive_frame(video->avCodecContext, avFrame) != 0) {
            av_frame_free(&avFrame);
            av_free(avFrame);

            av_packet_free(&avPacket);
            av_free(avPacket);
            continue;
        };
        LOGE("子线程解码一个avFrame 成功");

        if (avFrame->format == AV_PIX_FMT_YUV420P) {//如果是YUV420p  直接渲染

            LOGE("当前视频是YUV420P格式");
            video->mineCallJava->onCallRenderYuv(
                    video->avCodecContext->width,video->avCodecContext->height,
                    avFrame->data[0],avFrame->data[1],avFrame->data[2]);

        } else {
            //不是YUV420P格式的，需要将格式转换为YUV420P
            LOGE("当前视频是其他格式");
            AVFrame *frameYuv420 = av_frame_alloc();
            int num = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
                                               video->avCodecContext->width,
                                               video->avCodecContext->height,
                                               1);//对齐格式
            uint8_t *buffer = static_cast<uint8_t *>(av_malloc(num * sizeof(uint8_t)));
            av_image_fill_arrays(
                    frameYuv420->data,
                    frameYuv420->linesize,
                    buffer,
                    AV_PIX_FMT_YUV420P,
                    video->avCodecContext->width,
                    video->avCodecContext->height,
                    1);
            SwsContext *sws_context=sws_getContext(
                    video->avCodecContext->width,video->avCodecContext->height,video->avCodecContext->pix_fmt,
                    video->avCodecContext->width,video->avCodecContext->height,AV_PIX_FMT_YUV420P,
                    SWS_BICUBIC,//转码算法
                    NULL,NULL,NULL);
            if(!sws_context){
                av_frame_free(&frameYuv420);
                av_free(frameYuv420);
                av_free(buffer);
                continue;
            }
            sws_scale(sws_context,
                    avFrame->data,avFrame->linesize,0,avFrame->height,
                    frameYuv420->data,frameYuv420->linesize
                    );
            //渲染

            video->mineCallJava->onCallRenderYuv(
                    video->avCodecContext->width,video->avCodecContext->height,
                    frameYuv420->data[0],frameYuv420->data[1],frameYuv420->data[2]);


            av_frame_free(&frameYuv420);
            av_free(frameYuv420);
            av_free(buffer);

            sws_freeContext(sws_context);
        }


        av_frame_free(&avFrame);
        av_free(avFrame);
        avFrame = NULL;
        av_packet_free(&avPacket);
        av_free(avPacket);
        avPacket = NULL;
    }

    pthread_exit(&video->thread_play);
}

void MineVideo::play() {
    pthread_create(&thread_play, NULL, playVideo, this);
}

void MineVideo::release() {
    if (NULL != queue) {
        delete (queue);
        queue = NULL;
    }
    if (NULL != avCodecContext) {
        avcodec_close(avCodecContext);
        avcodec_free_context(&avCodecContext);
        avCodecContext = NULL;
    }
    if (NULL != playStatus) {
        playStatus = NULL;
    }
}

